using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;

public class MobNavigationController : MonoBehaviour, ILogicAssigner
{
	private System.Random random = new System.Random();

	public Vector3[] sectorPoints;

	public float rotSpeed = 1f;

	public float walkSpeed = 1.5f;

	public float runSpeed = 3.5f;

	public float cSpeed;

	public float directionModifireTime = 1f;

	public Vector3 directionModifire;

	public LayerMask navigationMask;

	private NavMeshPath _path;

	private NavMeshObstacle obstacle;

	public bool walking;

	private MobWayPoint curentWayPoint;

	private Humanoid humanoid;

	public string lastLogicMessage;

	[SerializeField]
	private int cornerIndex;

	private List<MobWayPointCahedWays> cahedWay = new List<MobWayPointCahedWays>();

	private List<Vector3> _corners = new List<Vector3>();

	private Vector3 lastPath = Vector3.zero;

	private float path = 1f;

	private float maxPath = 1f;

	private Vector3 pointToWalk;

	private bool tryObstacle;

	private Vector3 newPos;

	private RaycastHit hit;

	private MobWayPoint nearestMobWalkPoint;

	private RaycastHit obstacleHit;

	private RaycastHit groundHit;

	private Vector3 newPos23;

	[HideInInspector]
	public Transform rotationTarget;

	private Vector3 last = Vector3.zero;

	private Vector3[] corners
	{
		get
		{
			return _corners.ToArray();
		}
		set
		{
			_corners.Clear();
			_corners.AddRange(value);
		}
	}

	public void OnLogicEvent(int name, params object[] args)
	{
		lastLogicMessage = ((mobLogicEvent)name).ToString();
		switch ((mobLogicEvent)name)
		{
		case mobLogicEvent.StopWalk:
			DisableNavigation();
			break;
		case mobLogicEvent.StartWalk:
			base.enabled = true;
			StartMoving(walkSpeed);
			break;
		case mobLogicEvent.StartRun:
			StartMoving(runSpeed);
			break;
		case mobLogicEvent.StartIdle:
			break;
		case mobLogicEvent.Enable:
			break;
		case mobLogicEvent.Disable:
			base.enabled = false;
			DisableNavigation();
			break;
		case mobLogicEvent.PlaceMob:
			PlaceMob((Vector3)args[0], (Quaternion)args[1]);
			break;
		case mobLogicEvent.GoToNearestWalkPoint:
			GoToNearestWalkPoint();
			break;
		case mobLogicEvent.GoToNextWalkPoint:
			GoToNextPoint();
			break;
		case mobLogicEvent.GoToRandomPoint:
			GoToRandomPoint();
			break;
		case mobLogicEvent.SendEnableObstacle:
			SendEnableObstacle();
			break;
		case mobLogicEvent.GoToTarget:
			GoToTarget((Transform)args[0], (float)args[1]);
			break;
		case mobLogicEvent.WarpToRandomSpawnPoint:
			Warp();
			break;
		case mobLogicEvent.FindNewPath:
			ClearPath();
			GoToNextPoint();
			break;
		case mobLogicEvent.ShowGun:
		case mobLogicEvent.CalculateNewPath:
		case mobLogicEvent.ObstaclePlayer:
		case mobLogicEvent.ObstacleMob:
		case mobLogicEvent.ObstacleCar:
		case mobLogicEvent.TryfindNewPathForCurentPoint:
			break;
		}
	}

	public void SendToLogic(mobAssignerEvent name, params object[] args)
	{
		if (humanoid is EnemyBehavior)
		{
			((EnemyBehavior)humanoid).SendToLogic((int)name, args);
		}
	}

	public void PlaceMob(Vector3 position, Quaternion rotation)
	{
		base.transform.position = position;
		base.transform.rotation = rotation;
	}

	private void Awake()
	{
		_path = new NavMeshPath();
		humanoid = GetComponent<Humanoid>();
		if (humanoid is EnemyBehavior)
		{
			((EnemyBehavior)humanoid).logicController.AddAssigner(this);
		}
	}

	public void StartMoving(float speed)
	{
		cSpeed = speed;
		walking = true;
		base.enabled = true;
		StopAllCoroutines();
		StartCoroutine(checkObstacles());
	}

	private void TryGetNewPathForThisPoint()
	{
		if (NavMesh.CalculatePath(base.transform.position, pointToWalk, navigationMask, _path))
		{
			ClearPath();
			SetNewPath(_path.corners);
		}
	}

	private void SendEnableObstacle()
	{
		if (walking && obstacleHit.collider != null)
		{
			obstacle = obstacleHit.collider.GetComponentInParent<NavMeshObstacle>();
			MobNavigationController componentInParent = obstacleHit.collider.GetComponentInParent<MobNavigationController>();
			if (componentInParent != null)
			{
				componentInParent.EnableObstacle();
			}
			if (obstacle != null)
			{
				obstacle.enabled = true;
			}
			Invoke("ResetObstacle", 0.1f);
		}
	}

	public void EnableObstacle()
	{
		Invoke("ResetObstacle", 0.5f);
	}

	private void ResetObstacle()
	{
		TryGetNewPathForThisPoint();
		if (obstacle != null)
		{
			obstacle.enabled = false;
		}
	}

	public void DisableNavigation()
	{
		ClearPath();
		walking = false;
		SetNewPoint(base.transform.position);
		pointToWalk = base.transform.position;
		StopAllCoroutines();
	}

	public void GoToTarget(Vector3 target)
	{
		ClearPath();
		if (CalculatePath(target))
		{
			SetNewPath(_path.corners);
		}
	}

	public void GoToTarget(Transform target, float dist)
	{
		ClearPath();
		StartCoroutine(UpdatePathToTarget(target, dist));
	}

	private IEnumerator UpdatePathToTarget(Transform target, float dist)
	{
		newPos = target.position;
		while (walking)
		{
			newPos = target.position + (target.position - base.transform.position).normalized * dist;
			if (CalculatePath(newPos))
			{
				SetNewPath(_path.corners);
			}
			else
			{
				yield return new WaitForSeconds(UnityEngine.Random.Range(0.5f, 1f));
				newPos = target.position + (target.position - base.transform.position).normalized * Vector3.Distance(base.transform.position, newPos) / 2f;
				if (Physics.Raycast(newPos, Vector3.down, out hit, (int)navigationMask))
				{
					newPos.y = hit.point.y;
				}
				if (CalculatePath(newPos))
				{
					SetNewPath(_path.corners);
				}
				else
				{
					ClearPath();
					yield return new WaitForSeconds(UnityEngine.Random.Range(0.5f, 1f));
				}
			}
			yield return new WaitForSeconds(UnityEngine.Random.Range(0.8f, 1.2f));
		}
	}

	public bool CalculatePath(Vector3 target)
	{
		return NavMesh.CalculatePath(base.transform.position, target, navigationMask, _path);
	}

	private void Warp()
	{
		if (sectorPoints != null)
		{
			BCWDebug.LogError("WARP");
			RaycastHit hitInfo;
			if (Physics.Raycast(sectorPoints[random.Next(0, sectorPoints.Length)], Vector3.down, out hitInfo, 1000f))
			{
				base.transform.position = hitInfo.point;
				SendToLogic(mobAssignerEvent.PathIsOver);
			}
		}
	}

	private void GoToRandomPoint()
	{
		nearestMobWalkPoint = MobWayPointController.instance.points[UnityEngine.Random.Range(0, MobWayPointController.instance.points.Length)];
		Vector3 destanationPoint = nearestMobWalkPoint.GetDestanationPoint();
		if (CalculatePath(destanationPoint))
		{
			SetNewPath(_path.corners);
			return;
		}
		BCWDebug.LogError("can't go random point " + nearestMobWalkPoint.name + destanationPoint);
		GoToAnyAwailablePoint();
	}

	private void GoToAnyAwailablePoint()
	{
		if (MobWayPointController.instance.points.Length == 0)
		{
			return;
		}
		for (int i = 0; i < MobWayPointController.instance.points.Length; i++)
		{
			nearestMobWalkPoint = MobWayPointController.instance.points[i];
			Vector3 destanationPoint = nearestMobWalkPoint.GetDestanationPoint();
			if (CalculatePath(destanationPoint))
			{
				SetNewPath(_path.corners);
				return;
			}
		}
		BCWDebug.LogError("can't go to any point");
		OnLogicEvent(3);
	}

	private void GetNewWalkPath()
	{
	}

	private void GoToNearestWalkPoint()
	{
		ClearPath();
		nearestMobWalkPoint = GetNearestPoint();
		for (int i = 0; i < 5; i++)
		{
			Vector3 destanationPoint = nearestMobWalkPoint.GetDestanationPoint();
			if (CalculatePath(destanationPoint))
			{
				SetNewPath(_path.corners);
				return;
			}
		}
		OnLogicEvent(4);
	}

	private MobWayPoint GetNearestPoint()
	{
		MobWayPoint mobWayPoint = MobWayPointController.instance.points[0];
		float num = Vector3.Distance(base.transform.position, mobWayPoint.transform.position);
		for (int i = 1; i < MobWayPointController.instance.points.Length; i++)
		{
			float num2 = Vector3.Distance(MobWayPointController.instance.points[i].transform.position, base.transform.position);
			if (num > num2)
			{
				mobWayPoint = MobWayPointController.instance.points[i];
				num = num2;
			}
		}
		return mobWayPoint;
	}

	private void GoToNextPoint()
	{
		if (SetNextCashedWayPoint())
		{
			return;
		}
		if (nearestMobWalkPoint == null && MobWayPointController.instance == null)
		{
			float num = 0f;
			humanoid = GetComponent<EnemyBehavior>();
			if (humanoid != null)
			{
				num = ((EnemyBehavior)humanoid).enemyAreaBehavior.aggressiveDistance * 0.8f;
				GoToTarget(GameController.instance.playerScript.transform, num);
			}
		}
		else
		{
			SetCashedWayPoints(nearestMobWalkPoint.GetRandomPathFromThisPoint());
		}
	}

	private void FindAvaiblePoint(int rand)
	{
		for (int i = 0; i < sectorPoints.Length; i++)
		{
			if (i != rand && CalculatePath(sectorPoints[i]))
			{
				return;
			}
		}
		SendToLogic(mobAssignerEvent.CanNotFindPathToAnyPoint);
	}

	private void ClearPath()
	{
		lastPath = Vector3.zero;
		path = 1f;
		cahedWay.Clear();
		corners = new Vector3[0];
	}

	private void SetCashedWayPoints(List<MobWayPointCahedWays> points)
	{
		cahedWay = points;
		SetNewPath(cahedWay[0].corners.ToArray());
	}

	private bool SetNextCashedWayPoint()
	{
		if (cahedWay.Count > 0)
		{
			nearestMobWalkPoint = cahedWay[0].endMobWayPoint;
			SetNewPath(cahedWay[0].corners.ToArray());
			cahedWay.RemoveAt(0);
			return true;
		}
		return false;
	}

	private bool SetNextCorner()
	{
		cornerIndex++;
		path = 1f;
		maxPath = 1f;
		if (cornerIndex < corners.Length)
		{
			SetNewPoint(corners[cornerIndex]);
			return true;
		}
		SendToLogic(mobAssignerEvent.ImOnMobWayPoint);
		return false;
	}

	public void SetNewPoint(Vector3 point)
	{
		pointToWalk = point;
		pointToWalk.y = base.transform.position.y;
		maxPath = Vector3.Distance(base.transform.position, point);
		path = maxPath;
	}

	private void SetNewPath(Vector3[] corners)
	{
		if (corners.Length != this.corners.Length || corners.Select((Vector3 vec, int ind) => (double)Vector3.SqrMagnitude(vec - this.corners[ind]) >= 0.0001).Any((bool x) => x))
		{
			cornerIndex = 0;
			this.corners = corners;
			SetNewPoint(corners[0]);
		}
		else
		{
			SetNextCorner();
		}
	}

	private IEnumerator checkObstacles()
	{
		yield return new WaitForSeconds(0.1f);
		while (true)
		{
			if (Physics.Linecast(base.transform.position + Vector3.up, base.transform.position + Vector3.up + (pointToWalk - base.transform.position).normalized * 3f, out obstacleHit, navigationMask) && !obstacleHit.collider.isTrigger)
			{
				if (obstacleHit.collider.GetComponentInParent<PlayerBehavior>() != null)
				{
					SendToLogic(mobAssignerEvent.ObstaclePlayer);
				}
				else if (obstacleHit.collider.GetComponentInParent<EntityBehavior>() != null)
				{
					SendToLogic(mobAssignerEvent.ObstacleCar);
				}
				else if (obstacleHit.collider.GetComponentInParent<EnemyBehavior>() != null)
				{
					SendToLogic(mobAssignerEvent.ObstacleMob);
					yield return new WaitForSeconds(1f);
				}
				else if (obstacleHit.distance < 1f)
				{
					SendToLogic(mobAssignerEvent.ObstacleWall);
					yield return new WaitForSeconds(1f);
				}
			}
			yield return new WaitForSeconds(0.1f);
		}
	}

	private void InvokeImStuck()
	{
		SendToLogic(mobAssignerEvent.ImStuck);
		CancelInvoke("InvokeImStuck");
	}

	private void Update()
	{
		if (walking && Time.timeScale != 0f)
		{
			if (_corners.Count > cornerIndex)
			{
				pointToWalk = _corners[cornerIndex];
			}
			else
			{
				SetNextCorner();
			}
			if (path == 0f)
			{
				OnLogicEvent(14);
				return;
			}
			newPos23 = Vector3.Lerp(base.transform.position, pointToWalk, Time.deltaTime * cSpeed / path);
			lastPath = base.transform.position - newPos23;
			path -= lastPath.magnitude;
			if (path < 0.001f)
			{
				SetNextCorner();
				return;
			}
			if (lastPath.magnitude < 0.001f)
			{
				Invoke("InvokeImStuck", 0.2f);
				return;
			}
			CancelInvoke("InvokeImStuck");
			if (Time.frameCount % 10 == 0 && Physics.Raycast(base.transform.position + Vector3.up, Vector3.down, out groundHit, 5f, navigationMask) && !groundHit.collider.isTrigger)
			{
				newPos23.y = groundHit.point.y;
			}
			if (!float.IsNaN(newPos23.x) && !float.IsNaN(newPos23.y) && !float.IsNaN(newPos23.z))
			{
				base.transform.position = newPos23;
			}
			rotateToTarget(pointToWalk);
		}
		else if (rotationTarget != null)
		{
			rotateToTarget(rotationTarget.position);
		}
	}

	private void OnDrawGizmos()
	{
		if (_path == null || corners.Length <= 0)
		{
			return;
		}
		Gizmos.color = Color.green;
		Gizmos.DrawLine(base.transform.position, corners[0]);
		Gizmos.color *= 2f;
		for (int i = 0; i < corners.Length; i++)
		{
			if (last != Vector3.zero)
			{
				Gizmos.DrawLine(last, corners[i]);
			}
			last = corners[i];
		}
		last = Vector3.zero;
	}

	public void rotateToTarget(Vector3 destination)
	{
		if (destination != Vector3.zero)
		{
			destination.y = base.transform.position.y;
			if (destination - base.transform.position != Vector3.zero)
			{
				Quaternion b = Quaternion.LookRotation(destination - base.transform.position);
				base.transform.rotation = Quaternion.Lerp(base.transform.rotation, b, rotSpeed * Time.deltaTime);
			}
		}
	}
}
